home *** CD-ROM | disk | FTP | other *** search
- %
- % "eigenval.t" computes algebraic eigenvalues
- % using QR decomposition
- %
- % adapted from:
- % "C Tools for Scientists and Engineers" by L. Baker
- %
- % Sample program for the T Interpreter by:
- %
- % Stephen R. Schmitt
- % 962 Depot Road
- % Boxborough, MA 01719
- %
-
- var macheps : real := 0.00000001
- const DIM : int := 3
-
- type rmatrix : array[DIM,DIM] of real
- type ivector : array[DIM] of int
- type rvector : array[DIM] of real
-
- var A : rmatrix
-
- program
-
- var wr, wi : rvector
- var z : rmatrix
- var i : int
- var iwork, cnt : ivector
-
- put "array 1:"
-
- A[0,0] := 2
- A[0,1] := 2
- A[0,2] := 1
-
- A[1,0] := 1
- A[1,1] := 3
- A[1,2] := 1
-
- A[2,0] := 1
- A[2,1] := 2
- A[2,2] := 2
- print_matrix( A )
-
- eigenvv( A, iwork, z, wr, wi, cnt )
-
- put ""
- put "eigenvalues for array 1:"
- put ""
-
- for i := 0...DIM-1 do
- put complex_str( wr[i], wi[i] ), " it = ", cnt[i]
- end for
-
-
-
- put ""
- put ""
- put "array 2:"
-
- A[0,0] := 2
- A[0,1] := 4
- A[0,2] := 4
-
- A[1,0] := 0
- A[1,1] := 3
- A[1,2] := 1
-
- A[2,0] := 0
- A[2,1] := 1
- A[2,2] := 3
- print_matrix( A )
-
- eigenvv( A, iwork, z, wr, wi, cnt )
-
- put ""
- put "eigenvalues for array 2:"
- put ""
-
- for i := 0...DIM-1 do
- put complex_str( wr[i], wi[i] ), " it = ", cnt[i]
- end for
-
-
-
- put ""
- put ""
- put "array 3:"
-
- A[0,0] := 5
- A[0,1] := -4
- A[0,2] := -7
-
- A[1,0] := -4
- A[1,1] := 2
- A[1,2] := -4
-
- A[2,0] := -7
- A[2,1] := -4
- A[2,2] := 5
- print_matrix( A )
-
- put ""
- put "eigenvalues for array 3:"
- put ""
-
- eigenvv( A, iwork, z, wr, wi, cnt )
-
- for i := 0...DIM-1 do
- put complex_str( wr[i], wi[i] ), " it = ", cnt[i]
- end for
-
-
-
- put ""
- put ""
- put "array 4:"
-
- A[0,0] := 1
- A[0,1] := -1
- A[0,2] := -1
-
- A[1,0] := 1
- A[1,1] := -1
- A[1,2] := 0
-
- A[2,0] := 1
- A[2,1] := 0
- A[2,2] := -1
- print_matrix( A )
-
- put ""
- put "eigenvalues for array 4:"
- put ""
-
- eigenvv( A, iwork, z, wr, wi, cnt )
-
- for i := 0...DIM-1 do
- put complex_str( wr[i], wi[i] ), " it = ", cnt[i]
- end for
-
- end program
-
- %
- % compute eigenvalues and eigenvectors of a matrix
- %
- procedure eigenvv( var a : rmatrix,
- var iwork : ivector,
- var z : rmatrix,
- var wr, wi : rvector,
- var cnt : ivector )
-
- var ierr : int
-
- elmhes( a, iwork )
-
- eltran( a, iwork, z )
-
- hqr2( a, wr, wi, z, ierr, cnt )
-
- if ierr ~= 0 then
-
- put "ierr = ", ierr
-
- end if
-
- end procedure
-
- %
- % convert a general matrix to Hessenberg form
- %
- procedure elmhes( var a : rmatrix, var intar : ivector )
-
- var i, j, m, la, kp1, mm1, mp1 : int
- var x, y : real
-
- la := DIM - 2
- kp1 := 1
-
- if la < kp1 then
- return
- end if
-
- for m := kp1...la do
-
- mm1 := m - 1
- x := 0.0
- i := m
-
- for j := m...DIM-1 do
-
- if rabs( a[j,mm1] ) > rabs( x ) then
-
- x := a[j,mm1]
- i := j
-
- end if
-
- end for
-
- intar[m] := i
-
- if i ~= m then
-
- for j := mm1...DIM-1 do
-
- y := a[i,j]
- a[i,j] := a[m,j]
- a[m,j] := y
-
- end for
-
- for j := 0...DIM-1 do
-
- y := a[j,i]
- a[j,i] := a[j,m]
- a[j,m] := y
-
- end for
-
- end if
-
- if x ~= 0.0 then
-
- mp1 := m + 1
-
- for i := mp1...DIM-1 do
-
- y := a[i,mm1]
-
- if y ~= 0.0 then
-
- y := y / x
- a[i,mm1] := y
-
- for j := m...DIM-1 do
-
- a[i,j] := a[i,j] - y * a[m,j]
-
- end for
-
- for j := 0...DIM-1 do
-
- a[j,m] := a[j,m] + y * a[j,i]
-
- end for
-
- end if
-
- end for
-
- end if
-
- end for
-
- end procedure
-
- %
- % create transform matrix using results of elmhes
- %
- procedure eltran( var a : rmatrix,
- var intar : ivector,
- var z : rmatrix )
-
- var i, j, k, l, kl, mn, mp, mp1 : int
-
- % set z to identity matrix
- for i := 0...DIM-1 do
-
- for j := 0...DIM-1 do
-
- z[i,j] := 0.0
-
- end for
-
- z[i,i] := 1.0
-
- end for
-
- kl := DIM - 2
-
- if kl < 1 then
-
- return
-
- end if
-
- for decreasing i := DIM-2...1 do
-
- j := intar[i]
- for k := i+1...DIM-1 do
-
- z[k,i] := a[k,i-1]
-
- end for
-
- if i ~= j then
-
- for k := i...DIM-1 do
-
- z[i,k] := z[j,k]
- z[j,k] := 0.0
-
- end for
-
- z[j,i] := 1.0
-
- end if
-
- end for
-
- end procedure
-
- %
- % apply QR method to Hessenberg matrix
- %
- procedure hqr2( var h : rmatrix,
- var wr, wi : rvector,
- var vecs : rmatrix,
- var ierr : int,
- var cnt : ivector )
-
- var i, j, k, l, m, ii, jj, kk, mm, na, nm, nn, its, mpr, enm2, en : int
- var it1, it2, itlim : int
- var p, q, r, s, t, w, x, y, z, ra, sa, vi, vr, norm : real
- var xr, yr, xi, yi, zr, zi : real
- var notlast : boolean
- label nextw:
- label nextit:
- label break1:
-
- it1 := 10
- it2 := 20
- itlim := 30
- ierr := 0
-
- norm := 0.0
- k := 0
-
- for i := 0...DIM-1 do
-
- for j := k...DIM-1 do
-
- norm := norm + rabs( h[i,j] )
-
- end for
-
- k := i
- cnt[i] := 0
-
- end for
-
- assert norm > 0.0
-
- en := DIM-1
- t := 0.0
-
- nextw:
-
- watch( en )
-
- if en >= 0 then
-
- its := 0
- na := en - 1
- enm2 := na - 1
-
- nextit:
-
- for decreasing l := en...1 do
-
- s := rabs( h[l-1,l-1] ) + rabs( h[l,l] )
-
- if s = 0.0 then
-
- s := norm
-
- end if
-
- if rabs( h[l,l-1] ) <= s * macheps then
-
- goto break1
-
- end if
-
- end for
-
- l := 0
-
- break1:
-
- x := h[en,en]
-
- watch( l )
-
- if l = en then % found single a root
-
- wr[en] := x + t
- wi[en] := 0.0
- h[en,en] := x + t
- cnt[en] := its
- en := na
- goto nextw
-
- end if
-
- y := h[na,na]
- w := h[en,na] * h[na,en]
-
- if l ~= na then
-
- if its = itlim then
-
- cnt[en] := 31
- ierr := en
- return
-
- end if
-
- if its = it1 or its = it2 then
-
- t := t + x
- for i := 0...en do
-
- h[i,i] := h[i,i] - x
-
- end for
-
- s := rabs( h[en,na] ) + rabs( h[na,en-2] )
- x := 0.75 * s
- y := x
- w := -0.4375 * s * s
-
- end if
-
- incr its
-
- for decreasing m := en-2...l do
-
- mm := m + 1
- z := h[m,m]
- r := x - z
- s := y - z
- p := ( r * s - w ) / ( h[mm,m] ) + h[m,mm]
- q := h[mm,mm] - z - r - s
- r := h[m+2,mm]
- s := rabs( p ) + rabs( q ) + rabs( r )
- p := p / s
- q := q / s
- r := r / s
-
- if m = l then
-
- exit
-
- end if
-
- if rabs( h[m,m-1] ) * ( rabs( q ) + rabs( r ) ) <=
- macheps * rabs( p ) *
- ( rabs( h[m-1,m-1] ) + rabs( z ) + rabs( h[mm,mm] ) )
- then
-
- exit
-
- end if
-
- end for
-
- for i := m+2...en do
-
- h[i,i-2] := 0.0
-
- end for
-
- for i := m+3...en do
-
- h[i,i-3] := 0.0
-
- end for
-
- for k := m...na do
-
- notlast := k ~= na
-
- if k ~= m then
-
- p := h[k,k-1]
- q := h[k+1,k-1]
-
- if notlast then
-
- r := h[k+2,k-1]
-
- else
-
- r := 0.0
-
- end if
-
- x := rabs( r ) + rabs( q ) + rabs( p )
-
- if x = 0.0 then
-
- exit
-
- end if
-
- p := p / x
- q := q / x
- r := r / x
-
- end if
-
- s := sqrt( p * p + q * q + r * r )
-
- if p < 0.0 then
-
- s := -s
-
- end if
-
- if k ~= m then
-
- h[k,k-1] := -s * x
-
- elsif l ~= m then
-
- h[k,k-1] := -h[k,k-1]
-
- end if
-
- p := p + s
-
- x := p / s
- y := q / s
- z := r / s
-
- q := q / p
- r := r / p
-
- % row modification
-
- for j := k...DIM-1 do
-
- p := h[k,j] + q * h[k+1,j]
-
- if notlast then
-
- p := p + r * h[k+2,j]
- h[k+2,j] := h[k+2,j] - p * z
-
- end if
-
- h[k+1,j] := h[k+1,j] - p * y
- h[k,j] := h[k,j] - p * x
-
- end for
-
- % column modification
-
- if k + 3 < en then
-
- j := k + 3
-
- else
-
- j := en
-
- end if
-
- for i := 0...j do
-
- p := x * h[i,k] + y * h[i,k+1]
-
- if notlast then
-
- p := p + z * h[i,k+2]
- h[i,k+2] := h[i,k+2] - p * r
-
- end if
-
- h[i,k+1] := h[i,k+1] - p * q
- h[i,k] := h[i,k] - p
-
- end for
-
- % accumulate
-
- for i := 0...DIM-1 do
-
- p := x * vecs[i,k] + y * vecs[i,k+1]
-
- if notlast then
-
- p := p + z * vecs[i,k+2]
- vecs[i,k+2] := vecs[i,k+2] - p * r
-
- end if
-
- vecs[i,k+1] := vecs[i,k+1] - p * q
- vecs[i,k] := vecs[i,k] - p
-
- end for
-
- end for % k
-
- goto nextit
-
- end if % l ~= na
-
- % else two roots were found
-
- p := 0.5 * ( y - x )
- q := p * p + w
- z := sqrt( rabs( q ) )
- x := x + t
- h[en,en] := x
- h[na,na] := y + t
- cnt[en] := -its
- cnt[na] := its
-
- if q >= 0.0 then % real pair of roots
-
- if p < 0.0 then
-
- z := p - z
-
- else
-
- z := p + z
-
- end if
-
- wr[na] := x + z
- wr[en] := wr[na]
-
- if z ~= 0.0 then
-
- s := x - w / z
- wr[en] := s
-
- end if
-
- wi[en] := 0.0
- wi[na] := 0.0
-
- x := h[en,na]
- s := rabs( x ) + rabs( z )
- p := x / s
- q := z / s
- r := sqrt( p * p + q * q )
- p := p / r
- q := q / r
-
- for j := na...DIM-1 do
-
- z := h[na,j]
- h[na,j] := q * z + p * h[en,j]
- h[en,j] := q * h[en,j] - p * z
-
- end for
-
- for i := 0...en do
-
- z := h[i,na]
- h[i,na] := q * z + p * h[i,en]
- h[i,en] := q * h[i,en] - p * z
-
- end for
-
- for i := 0...DIM-1 do
-
- z := vecs[i,na]
- vecs[i,na] := q * z + p * vecs[i,en]
- vecs[i,en] := q * vecs[i,en] - p * z
-
- end for
-
- else % complex pair of roots
-
- wr[en] := x + p
- wr[na] := x + p
- wi[na] := z
- wi[en] := -z
-
- end if
-
- decr en
- decr en
-
- goto nextw
-
- end if % en >= 0
-
- % all eigenvalues have been found
-
- end procedure
-
-
- %=====================================================================
- % some utility functions
- %=====================================================================
-
- %
- % return the absolute value of a real number
- %
- function rabs( x : real ) : real
-
- var rv : real
-
- if x < 0.0 then
-
- rv := -x
-
- else
-
- rv := x
-
- end if
-
- return rv
-
- end function
-
- %
- % print a real 2D matrix
- %
- procedure print_matrix( var a : rmatrix )
-
- var i, j, btm, top, count : int := 0
-
- put ""
-
- loop
-
- exit when btm >= DIM
-
- if DIM > btm + 8 then
-
- top := btm + 8
-
- else
-
- top := DIM
-
- end if
-
-
- put "matrix columns ", btm, " to ", top - 1
-
- for j := 0...DIM-1 do
-
- for i := btm...top-1 do
-
- put a[j,i]:15:6:3...
-
- end for
-
- put ""
-
- end for
-
- btm := btm + 8
-
- end loop
-
- end procedure
-
- %
- % convert complex number to a string
- %
- function complex_str( re, im : real ) : string
-
- var s : string
-
- if im >= 0.0 then
-
- s := erealstr(re,15,6,3) & " +" & erealstr(im,13,6,3) & "j"
-
- else
-
- im := -im
- s := erealstr(re,15,6,3) & " -" & erealstr(im,13,6,3) & "j"
-
- end if
-
- return s
-
- end function